/*
之前，还增加过：
	1.充放电电流值与阀门状态的读取
	2.阀门逻辑控制部分
	3.电池电压为条件的判断，来控制阀门
*/

/*
2021.9.14 
	增加AD采样，可读取P36反馈值，并作条件判断，超出一定的阈值，就关闭阀门
	其目的是测发电机刚发出来整流之后的电压值，作为发电机的一种检测机制，让发电机运行稳定，禁止超负荷运行
*/

/*
2021.9.18
	增加AD采样值的判断，一定要注意，AD采样的数值其实是字符串，要对数据处理
	同时为了增加判断的精确性，要把ADVolt定义为double类型
	而且这些判断需要的数值型需要计算的参数要放在主循环之内，因为每一次采样计算都要重新计算一次
*/


/*
2021.9.20
1.增加AD采样的滤波
	AD在采样时，容易出现某些采样值特别大或者特别小，所以要进行过滤，也就是滤波
	滤波有两种方法，一种是求一下平均值；一种是做一个限定，去掉特别大的值和特别小的值。
2.写一段滞回，不使用特定的某个值来进行判断，做一个状态判断，
	比如，当阀门处于关闭的状态时，采样电压小于0.8时才会打开；
		  当阀门处于打开状态时，采样电压大于1.2才会打开
*/

/*
2021.9.26
控制策略调整
	1、短接
	2、读取电压值，小于23.5，打开阀门，开始充电；大于25，关闭阀门，停止充电。
	3、读取电流值，超过1.5，直接关闭
	4、AD采样值，设置最后保护4.5
*/

/*
2021.10.28
消除按键抖动
	防止阀门关的时候没有关严，会漏气。
*/

#include "STC8G.h"
#include "intrins.h"

#define FOSC 22118400UL
#define BRT (65536 - FOSC / 9600 / 4)
//定义参考电压，也就是公式里的VCC
#define VREF 5000

volatile unsigned int TimingDelay;

bit busy;

unsigned char BatBuffer[16];
char BatPoint = 2;
char BatCmd[6] = {0x06, 0x01, 0x10, 0x00, 0x00, 0x17};
char BatRxState = 0;      //0:初始化
                          //1:收到包头0x01
                          //2:收到包头0x01 0x10
unsigned int BatVolt = 0; //电池组电压
unsigned int BatAmpe = 0;	//***
unsigned char BatTemp = 0;
unsigned char BatState = 0;
//声明几个要用到的全局变量
unsigned char ADCCnt = 0;
unsigned int ADCResult = 0;
double ADVolt = 0;
unsigned long int ADCSum=0;

//再声明几个函数，如果放在前面的话，声不声明都可以
void ADC_Init(void);
void ADC_Process(void);
unsigned int ADC_GetResult(unsigned char ch);
void Delay100ms();
void Delay_ms(unsigned int ms);


bit BatRx = 0;
unsigned int BatTimer; //电池轮询计时器

unsigned int Volt = 0;//控制阀门用
unsigned int Ampe = 0;

unsigned char HostBuffer[40];
char HostPoint = 2;
char HostRxState = 0; //0:初始化
                      //1:收到包头0xFE
                      //2:收到包头0xFE 0xFE
                      //3:收到包头0xFE 0xFE 0x55
                      //4:收到包头0xFE 0xFE 0x55 0xAA
unsigned char HostResp[24] = {0xFF, 0xFF, 0x55, 0xAA, 0x00, 0x03, 0x00, 0x10, 0xFF, 0xA1, 0xA0, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16};
bit HostRx = 0;

unsigned int EnableDelay = 0;
	
	
//构造对ADC数据进行处理的函数
void ADC_Process(void)
{
	//从AD通道来采集数据，并进行累加
	ADCSum+=ADC_GetResult(ADC_CHANNELP36);
	//计数器+1
	ADCCnt++;
	//当累积到16个数据时则开始处理
	if(ADCCnt==16)
	{			
		ADCCnt=0;
		
		//(ADCSum>>4)等价于(ADCSum/16)	
		//对16个数求平均值		
		ADCSum=ADCSum>>4;	
		
		//Vref为MCU工作电压，根据ADC计算公式计算
		ADCSum=ADCSum*VREF/1023;
		
		//保存转化结果并类型转换，方便显示
		ADCResult=(unsigned int)ADCSum;
		
		//清除AD暂存变量
		ADCSum=0;
		
		//想办法能让他直接显示出来
		HostResp[20] = ADCResult%10000/1000;
		HostResp[21] = ADCResult%1000/100;
	}	
}


//构造ADC初始化函数
void ADC_Init(void)
{
	//初始化P36
	P3_Mode_IN_HighZ(PIN_6);
	
	//ADCTIM位于扩展的RAM区域，所以需要将P_SW2的BIT设置为1，才可正常读写
	SetBits(P_SW2,EAXFR);	//允许访问特殊寄存器
	
	//ADC保持时间2，模拟采样时间32
	SetBits(ADCTIM,CSHOLD0|SMPDUTY4|SMPDUTY3|SMPDUTY2|SMPDUTY1|SMPDUTY0);
	ClrBits(P_SW2,EAXFR);	//关闭访问特殊功能寄存器
	
	ADC_RES=0;	  	//ADC数据寄存器清零
	ADC_RESL=0;
	
	//设置ADC工作频率Sysclk/2/16
	SetBits(ADCCFG,ADC_SPEED3|ADC_SPEED2|ADC_SPEED1|ADC_SPEED0);	
	
	//转换结果数据右对齐
	SetBits(ADCCFG,RESFMT);	
	
	//打开AD转换器电源
	SetBits(ADC_CONTR,ADC_POWER);		

	Delay_ms(2);	    //延时，等待ADC上电
}


//构造函数获得ADC转换的结果
unsigned int ADC_GetResult(unsigned char ch)
{
	unsigned int ADC_Value;
	//设置通道
	ClrBits(ADC_CONTR,ADC_CHS3|ADC_CHS2|ADC_CHS1|ADC_CHS0);
	SetBits(ADC_CONTR,ch);	
	//启动ADC
	SetBits(ADC_CONTR,ADC_START);
	//延时
  _nop_();                        
  _nop_();
  while (!(ADC_CONTR & ADC_FLAG));//等待AD转换完成
  ClrBits(ADC_CONTR,ADC_FLAG);    //清楚转换完成标记
	ADC_Value=ADC_RES;							//读取ADC高两位
	ADC_Value=(ADC_Value<<8)|ADC_RESL;//读取ADC低两位，并且数据合并
  return ADC_Value;               	  
}


char DataCheckSum(char *Buf, char num) reentrant
{
    char i;
    char CheckSum = 0;
    for (i = 0; i < num; i++)
    {
        CheckSum = CheckSum + Buf[i];
    }
    return CheckSum;
}

void UartIsr() interrupt 4
{
    if (TI)
    {
        TI = 0;
        busy = 0;
    }
    if (RI)
    {
        RI = 0;
        switch (HostRxState)
        {
        case 0:
            if (SBUF == 0xFE)
            {
                HostRxState = 1;
            }
            break;
        case 1:
            if (SBUF == 0xFE)
            {
                HostRxState = 2;
            }
            else
                HostRxState = 0;
            break;
        case 2:
            if (SBUF == 0x55)
            {
                HostBuffer[0] = SBUF;
                HostRxState = 3;
            }
            else
                HostRxState = 0;
            break;
        case 3:
            if (SBUF == 0xAA)
            {
                HostBuffer[1] = SBUF;
                HostPoint = 2;
                HostRxState = 4;
            }
            else
                HostRxState = 0;
            break;
        case 4:
            if (HostPoint < 12 || HostPoint < (HostBuffer[5] + 5))
            {
                HostBuffer[HostPoint] = SBUF;
                HostPoint++;
            }
            else if (HostPoint == (HostBuffer[5] + 5) && SBUF == 0x16 && HostBuffer[HostPoint - 1] == DataCheckSum(HostBuffer, HostPoint - 1))
            //else if (HostPoint ==12)
            {
                HostRxState = 0;
                HostRx = 1;
            }
            else
            {
                HostRxState = 0;
            }
            break;

        default:
            break;
        }
    }
}

void Uart2Isr() interrupt 8
{
    if (S2CON & 0x02)
    {
        S2CON &= ~0x02;
        busy = 0;
    }
    if (S2CON & 0x01)
    {
        S2CON &= ~0x01;
        switch (BatRxState)
        {
        case 0:
            if (S2BUF == 0x01)
            {
                BatBuffer[0] = S2BUF;
                BatRxState = 1;
            }
            break;
        case 1:
            if (S2BUF == 0x10)
            {
                BatBuffer[1] = S2BUF;
                BatPoint = 2;
                BatRxState = 2;
            }
            else
                BatRxState = 0;
            break;
        case 2:
            if (BatPoint < 14)
            {
                BatBuffer[BatPoint] = S2BUF;
                BatPoint++;
            }
            else
            {
                if (S2BUF == DataCheckSum(BatBuffer, 14))
                {
                    BatVolt = BatBuffer[2];
                    BatVolt = BatVolt << 8;
                    BatVolt = BatVolt + BatBuffer[3];				
					BatAmpe = BatBuffer[4];
					BatAmpe = BatAmpe << 8;
					BatAmpe = BatAmpe + BatBuffer[5];			
                    BatTemp = BatBuffer[12];
                    BatState = BatBuffer[10];
                    // BatRx = 1;
                }
                BatRxState = 0;
            }
            break;

        default:
            break;
        }
    }
}

void UartInit()
{
    //配置定时器2
    T2L = BRT;
    T2H = BRT >> 8;
    //配置UART1
    SCON = 0x50; //8位数据，允许接收
    AUXR = 0x15; //定时器2启动 1T模式 定时器2作为UART1波特率发生器
    //配置UART2
    S2CON = 0x10;
    //使能中断
    ES = 1;
    IE2 |= 0x01;
    busy = 0;
}

void UartSend(char dat)
{
    P15 = 1;
    IE2 &= 0xFE;
    busy = 1;
    SBUF = dat;
    while (busy)
        ;
    IE2 |= 0x01;
    P15 = 0;
}
void UartSendResp(char *Resp)
{
    char count;
    for (count = 0; count < 24; count++)
    {
        UartSend(Resp[count]);
    }
}

void Uart2Send(char dat)
{
    P37 = 1;
    ES = 0;
    busy = 1;
    S2BUF = dat;
    while (busy)
        ;
    ES = 1;
    P37 = 0;
}
void Uart2SendCmd(char *Cmd, char num)
{
    char i;
    for (i = 0; i < num; i++)
    {
        Uart2Send(Cmd[i]);
    }
    BatRxState = 0;
}

void TIM0Init()
{
    TMOD = 0x00; //模式0
    TL0 = 0x00;  //65536-12.000M/12/1000
    TH0 = 0xB8;
    TR0 = 1; //启动定时器
    ET0 = 1; //使能定时器中断
}

void TIM0_Isr() interrupt 1
{
    BatTimer++;
    if (TimingDelay != 0x00)
    {
        TimingDelay--;
    }
}

void Delay100ms()		//@22.1184MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 9;
	j = 104;
	k = 139;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}



void Delay_ms(unsigned int ms)
{
  unsigned int i;
  while( (ms--) != 0)
  {
    for(i = 0; i < 860; i++); 
  }             
}

void main()
{
	ADC_Init();			  //ADC初始化
    P1M1 = 0x00;
    P1M0 = 0xA2;
    P3M1 = 0x00;
    P3M0 = 0x8C;
    P_SW1 = 0x80; //RXD_3/P1.6, TXD_3/P1.7
    P15 = 0;
    UartInit();
    TIM0Init();
    EA = 1;
	

    while (1)
    {
      
	/*		发光二极管闪烁		*/
			P12 = 0;
			Delay100ms();				
			P12 = 1; 
			Delay100ms();	
			
			ADC_Process();													//ADC采集数据并处理
			Delay100ms();													//适当延时
			
			
			Volt = (BatBuffer[2]*256+BatBuffer[3])*10;  					//电池电压
			Ampe = (BatBuffer[4]*256+BatBuffer[5])*10;						//电池充放电电流
			ADVolt = ADCResult%10000/1000+ADCResult%1000/100*0.1;			//AD电压换算
			
	
			/*			阀门控制部分逻辑				*/

			if (P13 == 0 && ADVolt <= 4.5 && Ampe <=1500 ) 				//打开允许
				{	
					if(Volt<24950)
						{
							if(24950-Volt>50)
							{
								P32 = 1; 												//满足条件，阀门打开
								P33 = 0;
								if (P34)												//P34==1为条件
								{
									 Delay100ms();
									if (P34){
									 P33 = 0;
									 P32 = 1; 											//阀门继续打开
									 HostResp[19] = 1;									//串口屏显示打开
									}										
								}
								else
								{
									 P32 = 0;											//完成开启，不再给阀门供电
									 P33 = 0;
								}
							}
							else
							{
								P32 = 0;
								P33 = 0;
							}
						}
						else
						{
							if(Volt-24950>50)
							{
								P32 = 0;
								P33 = 1;
								HostResp[19] = 0;
							}
							else
							{
								P32 = 0;
								P33 = 0;
							}
						}
					
				 }
			  else
				{
					//EnableDelay = 0;
					if (P35)
					{
						Delay100ms();
						if (P35){
						P32 = 0;
						P33 = 1; 											//阀门关闭
					    HostResp[19] = 0;									//串口屏显示关闭
						}							
					}
					else
					{
						P32 = 0;											//完成关闭，不再给阀门供电
						P33 = 0;
					}
				 }
						
				
				
				
				
/*			收到主机发来的测试信号时，返回数据包的组成部分			*/
        if (HostRx == 1)
        {
					
            HostResp[12] = HostBuffer[10] + 1; //报文ID+1
					
					
            if ((BatState & 0x08) == 0x08)     //充电状态
            {
                HostResp[13] = 1;
            }
            else if ((BatState & 0x04) == 0x04) //放电状态
            {
                HostResp[13] = 2;
            }
            else
            {
                HostResp[13] = 0;
            }
						
						
            HostResp[14] = BatVolt & 0xff;                  //电压低位
            HostResp[15] = BatVolt >> 8;                    //电压高位
						
			HostResp[16] = BatAmpe & 0xff;					//电流低位
			HostResp[17] = BatAmpe >> 8;					//电流高位
						
            HostResp[18] = BatTemp;                         //温度
						
												
            HostResp[22] = DataCheckSum(&HostResp + 2, 20); //校验和计算
			Delay100ms();
            UartSendResp(HostResp);                         //报文发送
            HostRx = 0;
        }
				
	/*		一直向电池发送数据包		*/
        if (BatTimer >= 100)
        {
            Uart2SendCmd(BatCmd, 6);
            BatTimer = 0;
        }
    }
}

//FE FE 55 AA 00 03 00 07 FF 91 A0 11 56 A0 16 主机测试
